package com.oa.activiti.controller;

import java.io.ByteArrayInputStream;
import java.util.ArrayList;
import java.util.List;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.activiti.bpmn.converter.BpmnXMLConverter;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.editor.constants.ModelDataJsonConstants;
import org.activiti.editor.language.json.converter.BpmnJsonConverter;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.Model;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.oa.activiti.dto.ModelDto;
import com.oa.entity.ExtPageable;
import com.oa.entity.ExtjsAjaxResult;

@Controller
@RequestMapping("/model")
public class ModelController {
	@Resource
	private RepositoryService repositoryService;

	@GetMapping("/list")
	public @ResponseBody Page<ModelDto> modelList(ExtPageable pageable) {
		List<Model> models = repositoryService.createModelQuery().list();
		List<ModelDto> dtoList = null;

		if (models != null) {
			dtoList = new ArrayList<>();
			for (Model model : models) {
				ModelDto temp = new ModelDto();
				temp.setId(model.getId());
				temp.setName(model.getName());
				temp.setKey(model.getKey());
				temp.setCategory(model.getCategory());
				temp.setCreateTime(model.getCreateTime());
				temp.setLastUpdateTime(model.getLastUpdateTime());
				temp.setVersion(model.getVersion());
				temp.setMetaInfo(model.getMetaInfo());
				temp.setDeploymentId(model.getDeploymentId());
				temp.setTenantId(model.getTenantId());
				temp.setEditorSource(model.hasEditorSource());
				temp.setEditorSourceExtra(model.hasEditorSourceExtra());

				dtoList.add(temp);
			}
		}

		Page<ModelDto> modelsPageList = new PageImpl<>(dtoList, pageable.getPageable(),
				dtoList != null ? dtoList.size() : 0);

		return modelsPageList;
	}

	@SuppressWarnings("deprecation")
	@PostMapping("/create")
	@PreAuthorize("hasAnyAuthority('ADMIN','HIGH_MANAGER')")
	public @ResponseBody ExtjsAjaxResult create(String name, String key, String description,
			HttpServletRequest request) {
		try {
			ObjectMapper objectMapper = new ObjectMapper();
			ObjectNode editorNode = objectMapper.createObjectNode();
			editorNode.put("id", "canvas");
			editorNode.put("resourceId", "canvas");
			ObjectNode stencilSetNode = objectMapper.createObjectNode();
			stencilSetNode.put("namespace", "http://b3mn.org/stencilset/bpmn2.0#");
			editorNode.put("stencilset", stencilSetNode);
			Model modelData = repositoryService.newModel();

			ObjectNode modelObjectNode = objectMapper.createObjectNode();

			modelObjectNode.put(ModelDataJsonConstants.MODEL_NAME, name);
			modelObjectNode.put(ModelDataJsonConstants.MODEL_REVISION, 1);
			description = StringUtils.defaultString(description);
			modelObjectNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION, description);
			modelData.setMetaInfo(modelObjectNode.toString());
			modelData.setName(name);
			modelData.setKey(StringUtils.defaultString(key));

			repositoryService.saveModel(modelData);
			repositoryService.addModelEditorSource(modelData.getId(), editorNode.toString().getBytes("utf-8"));

			// response.sendRedirect(request.getContextPath() +
			// "/modeler.html?modelId=" + modelData.getId());
			return new ExtjsAjaxResult(true, request.getContextPath() + "/modeler.html?modelId=" + modelData.getId());// 前端window.open();
		} catch (Exception e) {
			e.printStackTrace();
			return new ExtjsAjaxResult(false, "创建模型失败!");
		}
	}

	@RequestMapping(value = "/deploy/{modelId}")
	@PreAuthorize("hasAnyAuthority('ADMIN','HIGH_MANAGER')")
	public @ResponseBody ExtjsAjaxResult deploy(@PathVariable("modelId") String modelId,
			RedirectAttributes redirectAttributes) {
		try {
			Model modelData = repositoryService.getModel(modelId);
			ObjectNode modelNode = (ObjectNode) new ObjectMapper()
					.readTree(repositoryService.getModelEditorSource(modelData.getId()));
			byte[] bpmnBytes = null;

			BpmnModel model = new BpmnJsonConverter().convertToBpmnModel(modelNode);
			bpmnBytes = new BpmnXMLConverter().convertToXML(model);

			String processName = modelData.getName() + ".bpmn20.xml";
			Deployment deployment = repositoryService.createDeployment().name(modelData.getName())
					.addString(processName, new String(bpmnBytes, "UTF-8")).deploy();

			return new ExtjsAjaxResult(true, "部署成功，部署ID=" + deployment.getId());
		} catch (Exception e) {
			e.printStackTrace();
			return new ExtjsAjaxResult(false, "根据模型部署流程失败：modelId=" + modelId);
		}
	}

	@RequestMapping(value = "/delete/{modelId}")
	@PreAuthorize("hasAnyAuthority('ADMIN','HIGH_MANAGER')")
	public @ResponseBody ExtjsAjaxResult delete(@PathVariable("modelId") String modelId) {
		try {
			repositoryService.deleteModel(modelId);
			return new ExtjsAjaxResult(true, "删除成功!");
		} catch (Exception e) {
			e.printStackTrace();
			return new ExtjsAjaxResult(false, "删除失败!");
		}
	}

	@RequestMapping(value = "/export/{modelId}/{type}")
	public void export(@PathVariable("modelId") String modelId, @PathVariable("type") String type,
			HttpServletResponse response) {
		try {
			Model modelData = repositoryService.getModel(modelId);
			BpmnJsonConverter jsonConverter = new BpmnJsonConverter();
			byte[] modelEditorSource = repositoryService.getModelEditorSource(modelData.getId());
			JsonNode editorNode = new ObjectMapper().readTree(modelEditorSource);
			BpmnModel bpmnModel = jsonConverter.convertToBpmnModel(editorNode);
			// 处理异常
			if (bpmnModel.getMainProcess() == null) {
				response.setStatus(HttpStatus.UNPROCESSABLE_ENTITY.value());
				response.getOutputStream().println("no main process, can't export for type: " + type);
				response.flushBuffer();
				return;
			}

			String filename = "";
			byte[] exportBytes = null;
			String mainProcessId = bpmnModel.getMainProcess().getId();

			if (type.equals("bpmn")) {
				BpmnXMLConverter xmlConverter = new BpmnXMLConverter();
				exportBytes = xmlConverter.convertToXML(bpmnModel);
				filename = mainProcessId + ".bpmn20.xml";
			} else if (type.equals("json")) {
				exportBytes = modelEditorSource;
				filename = mainProcessId + ".json";
			}

			ByteArrayInputStream in = new ByteArrayInputStream(exportBytes);
			response.setHeader("Content-Disposition", "attachment; filename=" + filename);
			response.setCharacterEncoding("UTF-8");

			IOUtils.copy(in, response.getOutputStream());
			response.flushBuffer();
			in.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
